#include "Engine.h"
#include "SceneSystem.h"
#include "EngineMessages.h"
#include "EngineProfileSample.h"
#include "EngineLog.h"

Engine::Engine(EnginePointer<ISystemConfiguration>& sysConfig, EnginePointer<SettingsManager>& settings)
{
	running = FALSE;

	this->settings = settings;

	entities = new EngineEntityCollection();
	components = new IEngineComponentCollection();
	systems = new SystemCollection();
	messages = new MessageQueue();

	sysConfig->InitializeSystems(systems, settings, (EnginePointer<IMessageQueue>&)messages);
	systems->GenerateLevels();
}

Engine::~Engine()
{
	entities->clear();
	settings = NULL;
	systems = NULL;
	messages = NULL;
}

HRESULT Engine::Initialize()
{
	HRESULT hr;

	for (IEngineComponentCollection::iterator it = components->begin(); it != components->end(); it++)
	{
		(*it)->Initialize(components);
	}

	hr = InitializeSystems();
	if (FAILED(hr)) return hr;

	initialized = TRUE;

	return S_OK;
}

HRESULT Engine::InitializeSystems()
{
	HRESULT hr;

	int levels = systems->getNumberOfLevels();

	for (int i = 0; i <= levels; i++)
	{
		for (list<EnginePointer<IEngineSystem>>::iterator it = systems->levelBegin(i); it != systems->levelEnd(i); it++)
		{
			hr = (*it)->Initialize(systems);
			if (FAILED(hr)) return hr;
		}
	}

	return S_OK;
}

void Engine::Run()
{
	running = TRUE;

	LARGE_INTEGER largeFreq;
	QueryPerformanceFrequency(&largeFreq);
	LONGLONG freq = largeFreq.QuadPart;
	LONGLONG start = 0;

	int levels = systems->getNumberOfLevels();
	
	while (running)
	{
		LARGE_INTEGER largeCurrent;
		LONGLONG current;
		QueryPerformanceCounter(&largeCurrent);
		current = largeCurrent.QuadPart;
		if (start == 0) start = current;
		LONGLONG t = ( current - start ) * 1000000 / freq;

		for (int i = 0; i <= levels && running; i++)
		{
			for (list<EnginePointer<IEngineSystem>>::iterator it = systems->levelBegin(i); it != systems->levelEnd(i) && running; it++)
			{
				(*it)->Update(t);
				while (messages->HasMessage())
				{
					Message m = messages->Dequeue();
					for (int k = 0; k <= levels; k++)
					{
						for (list<EnginePointer<IEngineSystem>>::iterator it2 = systems->levelBegin(k); it2 != systems->levelEnd(k); it2++)
						{
							(*it2)->DeliverMessage(m);
						}
					}
					DeliverMessage(m);
				}
			}
		}
		start = current;
	}

	for (int i = levels; i >= 0; i--)
	{
		for (list<EnginePointer<IEngineSystem>>::iterator it = systems->levelBegin(i); it != systems->levelEnd(i); it++)
		{
			(*it)->Clean();
			while (!(*it)->IsClean())
			{
				for (int k = i; k >= 0; k--)
				{
					for (list<EnginePointer<IEngineSystem>>::iterator it2 = it; it2 != systems->levelEnd(k); it2++)
					{
						(*it2)->Update(0);
					}
				}
			}
		}
	}
}

void Engine::DeliverMessage(Message m)
{
	if (strcmp(m.messageId, ENGINE_QUIT_MESSAGE) == 0)
	{
		running = FALSE;
	}
}

HRESULT Engine::AddEntity(EnginePointer<EngineEntity>& entity)
{
	HRESULT hr;

	entities->push_back(entity);
	for (IEngineComponentCollection::iterator it = entity->ComponentsBegin(); it != entity->ComponentsEnd(); it++)
	{
		components->push_back(*it);
	}
	if (initialized)
	{
		for (IEngineComponentCollection::iterator it = entity->ComponentsBegin(); it != entity->ComponentsEnd(); it++)
		{
			(*it)->Initialize(components);
		}
	}
	for (IEngineComponentCollection::iterator it = entity->ComponentsBegin(); it != entity->ComponentsEnd(); it++)
	{
		if (NULL_SYSTEM != (*it)->getSystemIdentifier())
		{
			EnginePointer<IEngineSystem> system = systems->getSystem((*it)->getSystemIdentifier());
			if (system.isValid())
			{
				hr = system->RegisterComponent(*it);
				if (FAILED(hr)) return hr;
			}
		}
	}

	return S_OK;
}
